#include <cserver/restapi.h>
#include <cserver/module.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <pqxx/transaction.hxx>
#include <cserver/iom.h>
#include <cserver/s11nbase.h>
#include <boost/lexical_cast.hpp>
#include <cserver/context.h>

#include <sstream>

namespace csrv{ namespace web_v2{ namespace {
	struct SqlRegister{
		SqlRegister(){
			{
			auto& sql = GetApiSqlTable()["v2_sql_horn_set_status"];
			sql.sql_name = "v2_sql_horn_set_status";
			sql.sql = "insert into t_horn_command_data(euid, time, command_type, create_by) "
				" select t_node_info2.id, localtimestamp, $1, $2 from t_node_info2 where t_node_info2.id=$3 and orgid=$4";
			}
			{
			auto& sql = GetApiSqlTable()["v2_sql_horn_get_ip_port"];
			sql.sql_name = "v2_sql_horn_get_ip_port";
			sql.sql = "select last_ip_port from t_node_info2 where id = $1";
			}
			{
			auto& sql = GetApiSqlTable()["v2_sql_horn_set_status2"];
			sql.sql_name = "v2_sql_horn_set_status2";

			sql.sql = "insert into t_horn_data(euid, time, signal, simid, status)"
						" values($1, localtimestamp, int2(0), '', 55) ";
			}
		}
	};
	SqlRegister k_sql_register;

	const char* K_this_command= "api/v2/horn/set_status";

	void set_horn_status(Request& req, pqxx::connection& dbconn, SessionContext& sctx, const std::string& /*cmd*/ ){
		auto query = parseQuery(req.getParam("QUERY_STRING"));
		auto& callback = query["callback"];
		auto sessionid = req.getCookie("sessionid");
		std::string userid, orgid;
		{
			std::lock_guard<std::mutex> guard(sctx.mutex);
			auto pos = sctx.sessionTable.find(sessionid);
			userid = pos->second.userid;
			orgid = pos->second.orgid;
		}

		StreamGroup sg(req, 4096);

		boost::property_tree::ptree ptree;
		read_json(sg.fin, ptree);

		auto euid = ptree.get<std::string>("euid", "");
		auto command_type = ptree.get<std::string>("command_type", "");
		if (euid.empty() || command_type.empty()){
			response_error(sg.fout, 400, "ErrParameter", "BadParameter", req);
			return;
		}
		pqxx::work w(dbconn);
		auto res1 = w.prepared("v2_sql_horn_get_ip_port")(euid).exec();
		std::string remote_addr;
		if (!res1.empty())
			remote_addr = res1.begin()->begin()->c_str();

		auto result = w.prepared("v2_sql_horn_set_status")(command_type)(userid)(euid)(orgid).exec();
		if (result.affected_rows() >0)
			w.prepared("v2_sql_horn_set_status2")(euid).exec();

		w.commit();

		response_header(sg.fout, 200);
		if (!callback.empty()) sg.fout << callback << "(";
		sg.fout << (R"({
"func":"set_horn_status",
"ret":{"success":
)") << (result.affected_rows() > 0 ? "true" : "false") << "}}";

			if (!callback.empty()) sg.fout << ")";

		if (!remote_addr.empty()){
			using namespace boost::asio::ip;
			auto colon = std::find(remote_addr.begin(), remote_addr.end(), ':');
			auto addr = address::from_string(std::string(remote_addr.begin(), colon));
			if (colon != remote_addr.end()) ++colon;
			auto port = boost::lexical_cast<uint16_t>(std::string(colon, remote_addr.end())); 
			udp::endpoint remote(addr, port); 
			udp::socket socket(req.context->ios_client);
			socket.open(udp::v4());

			std::vector<char> buf;
			buffer_out wr(buf);
			auto ar = s11n::as_sink(wr);
			ar & K_signature & K_version & K_reserved 
				& uint16_t(0x800a)
				& uint16_t(4)	// length 4
				& uint16_t(38)	// interval ID
				& uint8_t(boost::lexical_cast<uint32_t>(command_type));	 
			socket.send_to(boost::asio::buffer(buf), remote);
			BOOST_LOG_TRIVIAL(debug) <<"Horn send >>>> "<< remote << ",  " << command_type ;
		}

	}

	CommandAddHelper k_registerHandler("POST", web_v2::K_this_command, &web_v2::set_horn_status);
}}}


